package com.ics.atable.chat.node;

import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.action.NodeAction;
import com.ics.atable.chat.cache.HotKeyCache;
import com.ics.atable.chat.config.ChatClientServiceFactory;
import com.ics.atable.chat.model.dto.KeyWordExtract;
import com.ics.atable.chat.model.dto.SynonymsExtract;
import com.ics.atable.chat.prompt.PromptConstant;
import com.ics.atable.chat.service.SemanticModelService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.ai.chat.client.ChatClient;

import java.util.*;

import static com.alibaba.cloud.ai.graph.StateGraph.END;
import static com.ics.atable.chat.constant.ItemQueryConstant.*;

@Slf4j
public class SynonymsNode implements NodeAction {

    private final ChatClient synonymsClient;

    private final HotKeyCache hotKeyCache;

    private final SemanticModelService semanticModelService;

    public SynonymsNode(ChatClientServiceFactory chatClientServiceFactory, HotKeyCache hotKeyCache, SemanticModelService semanticModelService) {
        this.synonymsClient = chatClientServiceFactory.getOrCreateSynonymsChatClient();
        this.hotKeyCache = hotKeyCache;
        this.semanticModelService = semanticModelService;
    }

    @Override
    public Map<String, Object> apply(OverAllState state) throws Exception {
        Map<String, Object> updated = new HashMap<>();
        try{
            // 去除struct_token的map数据
            KeyWordExtract keyWordExtract = state.value("struct_token", KeyWordExtract.class)
                    .orElseThrow(() -> new IllegalArgumentException("struct_token is missing"));

            log.info("struct_token: {}", keyWordExtract);
            // 得到作物的名称
            List<String> item = keyWordExtract.getItems();
            if(CollectionUtils.isEmpty(item)) {
                item = keyWordExtract.getIndicators();
            }
            log.info("item: {}", item);
            // 拿到提示词
            String systemPrompt = PromptConstant.getSynonymsPromptTemplate().getTemplate();
            // 1.去缓存中遍历遍历所有item中的数据，缺失则记录下来让模型来生成
            List<String> missingItems = new ArrayList<>();
            List<List<String>> exitsItems = new ArrayList<>();
            for (String itemName : item) {
                // 1.1. 获取缓存中的数据
                String synonyms_cache = hotKeyCache.getCache(itemName, "synonyms", "atable-chat");
                log.info("synonyms_cache: {}", synonyms_cache);
                // 1.2. 如果缓存中没有数据，则进行记录，最后统一返回给大模型生成
                if (Objects.equals(synonyms_cache, "")) {
                    // 1.3. 将缺失的数添加到missingItems中
                    missingItems.add(itemName);
                } else{
                    // 1.4. 缓存中的数据要转化成List<String>
                    String trimmed = synonyms_cache.substring(1, synonyms_cache.length() - 1);
                    List<String> list = new ArrayList<>(Arrays.asList(trimmed.split(", ")));
                    // 1.5. 校验原有数据是否在里面，如果有则不添加，没有则添加
                    if (!list.contains(itemName)) {
                        list.add(itemName);
                    }
                    // 1.6. 然后添加到exitsItem中
                    exitsItems.add(list);
                }
             }
            log.info("missingItems: {}", missingItems);
            // 2. 模型生成完之后存到数据库中
            // 2.1. 判断missItems为空
            if (missingItems.isEmpty()){
                log.info("所有item的缓存数据已存在");
            } else{
                // 2.2. 大模型来生成同义词
                SynonymsExtract llm_response = synonymsClient.prompt()
                        .system(systemPrompt)
                        .user(missingItems.toString())
                        .call().
                        entity(SynonymsExtract.class);
                log.info("llm_response: {}", llm_response);
                // 2.3. 处理同义词，将单个数据匹配到的数据依次存入数据库中
                if (llm_response != null && llm_response.getSynonyms() != null && !llm_response.getSynonyms().isEmpty()) {
                    List<List<String>> synonymsList = llm_response.getSynonyms();
                    for (int i=0; i < missingItems.size(); i++) {
                        List<String> synonymGroup = synonymsList.get(i); // ["洋芋"]
                        List<String> mergedGroup = new ArrayList<>(); // 👈 创建新列表，不修改原始数据！
                        // 1. 从 LLM 返回中提取有效同义词（过滤掉空字符串）
                        if (synonymGroup != null) {
                            for (String syn : synonymGroup) {
//                                if (syn != null && !syn.trim().isEmpty()) { // 防止 "   " 也变成空
                                 if (syn != null && !syn.trim().isEmpty() && !syn.equals(missingItems.get(i))) { // 添加一个防大模型生成重复结果的部分
                                    mergedGroup.add(syn);
                                }
                            }
                        }
                        // 2. 添加原始关键词（保证至少有一个词）
                        String originalWord = missingItems.get(i);
                        Map<String, List<String>> saveSemanticMap = new HashMap<>();
                        saveSemanticMap.put(originalWord, mergedGroup);
                        log.info("saveSemanticMap: {}", saveSemanticMap);
                        // 2.4. 存至数据库中
                        semanticModelService.saveBySemanticMap(saveSemanticMap);
                        // 原数据不能存至数据库中
                        if (originalWord != null && !originalWord.trim().isEmpty()) {
                            mergedGroup.add(originalWord.trim());
                        }
                        // 3. 添加到结果
                        exitsItems.add(mergedGroup);
                    }
                }else{
                    // 大模型返回结果为空的话将元数据添加进去
                    exitsItems.add(item);
                }
            }
            // 3.将结果进行拼接形成一个List<List<String>>然后存到updated中
            log.info("exitsItems: {}", exitsItems);

            // 放至updated中
            keyWordExtract.setItems(item);
            keyWordExtract.setItemsWithSynonyms(exitsItems);
            updated.put("struct_token", keyWordExtract);

            updated.put(SYNONYMS_NEXT_NODE, ITEM_RETRIEVAL);
            return updated;
        }
        catch (Exception e){
            log.error("SynonymsNode error: {}", e.getMessage());
            updated.put("struct_token", "");
            // 出现错误直接结束
            updated.put(STRUCT_TOKEN_NEXT_NODE, END);
            updated.put("error", e.getMessage());
            return updated;
        }

    }
}
